#!/usr/bin/env python
"""Python wrapper classes for eBay's API.

services implemented :
- findItems http://developer.ebay.com/DevZone/finding/CallRef/findItemsByKeywords.html
"""

__authors__ = ['"Renaud Canarduck" <renaud@canarduck.com>']
__credits__ = ['Insert Many']
__license__ = 'WTFPL'
__version__ = '2'
__maintainer__ = 'Canarduck'
__email__ = 'renaud@canarduck.com'
__status__ = 'Alpha'

from xml.dom.minidom import Node, parse, parseString
import ConfigParser
import urllib
import urllib2
        
class API(object):

    """eBay API
    
    Attributes:
        conf: an array containing infos parsed at __init__ (api keys, etc...)
        eggs: An integer count of the eggs we have laid.
    """
    
    def __init__(self, config_file='ebay.ini'):
        """Parse config file
        
        Args:
            config_file: name of the config file
        """
        self.errors = []
        self.conf = {}
        c = ConfigParser.ConfigParser()
        c.read(config_file)  
        #TODO(canarduck): handle config parse exceptions and add a message if values are missing
        self.conf['developer'] = c.get('Developer Keys', 'Developer')
        self.conf['application'] = c.get('Developer Keys', 'Application')
        self.conf['certificate'] = c.get('Developer Keys', 'Certificate')
        self.conf['server_name'] = c.get("Server", "Name")
        self.conf['find_path'] = c.get("Services", "Find")
        self.conf['global_ID'] = c.get("Variables", "GlobalID")
        
    def _query(self, service, request_data):
        """Launch query against eBay servers
        
        Args:
            service: path of the service queried (set in config file [Services])
            request_data: a dictionary containing required arguments to build the request
        """
        
        request_data['SECURITY-APPNAME'] = self.conf['application']
        url = 'http://' + self.conf['server_name'] + service + urllib.urlencode(request_data)
        request = urllib2.Request(url)
        data = False
        try:
            f = urllib2.urlopen(request)
            data = f.read()
            f.close()
            return data
        except urllib2.HTTPError, e: # TODO(canarduck): handle most of the HTTPerrors
            if e.code == 301:
                raise EbayHTTPError, "HTTP error %s" % e.code
            return false
        
    def find(self, query):
        request_data = {
            'OPERATION-NAME':'findItemsByKeywords',
            'SERVICE-VERSION':'1.0.0',
            'GLOBAL-ID':self.conf['global_ID'],
            'keywords':query}
        data = self._query(self.conf['find_path'], request_data)
        items = []
        if data == False:
            pass # TODO(canarduck): check if an error can occur here
        else: 
            response = parseString(data)
            item_nodes = response.getElementsByTagName('item')
            for item in item_nodes:
                properties = {'id':item.getElementsByTagName('itemId')[0],
                    'title':item.getElementsByTagName('title')[0].childNodes[0].nodeValue,
                    'price':item.getElementsByTagName('currentPrice')[0].childNodes[0].nodeValue,
                    'ends':item.getElementsByTagName('timeLeft')[0].childNodes[0].nodeValue,
                    'link':item.getElementsByTagName('viewItemURL')[0].childNodes[0].nodeValue}
                try:
                    properties['image']  = item.getElementsByTagName('galleryURL')[0].childNodes[0].nodeValue
                except IndexError: # galleryURL occurrence is conditional
                    pass
                try:
                    properties['seller']  = item.getElementsByTagName('sellerUserName')[0].childNodes[0].nodeValue
                except IndexError: # seller info is conditional
                    pass
                try:
                    properties['shipping']  = item.getElementsByTagName('shippingInfo')[0].childNodes[0].nodeValue
                except IndexError: # shippingInfo is conditional
                    pass  
                items.append(properties)
        return items
        
class EbayError(Exception):
    """Used to indicate that an error occurred when trying to access ebay via its API."""
    pass
    
class EbayWarning(Exception):
    """Used to indicate that a warning occurred when trying to access ebay via its API."""
    pass

class EbayHTTPError(EbayError):
    """Used to indicate that an HTTP error occurred"""
    pass
    
if __name__ == "__main__":
    api = API()
    query = 'dj shadow endtroducing'
    print 'Search for "%s" on eBay' % query
    print '========================================================='
    results = api.find(query)
    print results